先了解什麼是Hoisting,也就是宣告提升。
此種行為現象主因,是由於js在初始編譯階段,先將變數&函式宣告式放入記憶體(此時無賦予值),而執行時可視為將變數與函式宣告式提升至作用域的最頂端。
範例:
b();
console.log(a);
var a = 'Hello World!';
function b() {
console.log('Called b!');
}
可視為:
function b() {
console.log('Called b!');
};
var a;
b();
console.log(a);
a = 'Hello World!';
注意!
常見定義函式有兩種
函式宣告式會整個提升,而函式運算式則只會提升等號左的變數,並不會提升等號右邊的函式
Hoisting 這個觀念主要是要了解 JavaScript 記憶體運作的觀念,實作上也會避免在 function 前方直接呼叫函式,這樣會降低對於程式碼的可維護性。
函式宣告式 : 在函式前方直接調用方法可運行
function call() {
console.log(123)
}
函式運算式 : 在函式前方直接調用方法不可運行
var call = function () {
console.log(123)
}
範例:
console.log(callSomeone); // undefined
callSomeone('杰倫哥'); // callSomeone is not a function
var callSomeone = function (name) {
console.log('打給 ' + name)
}
在 JS 中有稱作 scope chain(範圍鏈)的特性
JS在查找變數時 會循著範圍鏈(Scope Chain)一層一層往外找
若函式內找不到 則往外找
範例:
var cat = "cat"
function a(){
var cat = "kitty";
b()
}
function b(){
console.log(cat)
}
a() //cat
// 因b()函式在全域作用域,故直接抓全域下的變數cat
var cat = "cat"
function a(){
var cat = "kitty";
function b(){
console.log(cat)
}
b()
}
a() //kitty
// 因b()函式在a()函式作用域裡,故抓a()裡的變數cat
var cat = "cat"
function a(){
cat = "kitty";
b()
}
function b(){
console.log(cat)
}
a() //kitty
// 因a()函式內的cat變數無宣告,故汙染全域變數
var myVar = "outer";
function func(){
console.log(myVar); // outer
myVar = "inner";
}
func();
console.log(myVar); // inner
//在func()函數執行時,會先執行完console.log(myVar);後才汙染全域變數myVar